home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_11_08 / weber / dialog.c < prev    next >
C/C++ Source or Header  |  1993-03-11  |  67KB  |  1,741 lines

  1. /***************************************************************
  2.  * file: DIALOG.C
  3.  * purpose:
  4.  *  dialog box functions for simple gui
  5.  *      for now all dialog boxes are modal
  6.  * contains:
  7.  *  dialog_open(DIALOG_ITEM dialog[],short number_of_items,short loc_x,short loc_y,short width,short height);   draws a dialog box
  8.  *  dialog_message_handler(MESSAGE *message,DIALOG_ITEM *dialog);   handles dialog box messages
  9.  *  dialog_close(DIALOG_ITEM dialog[]);                             erases a dialog box
  10.  *  dialog_add_item(short type,void *data,DIALOG_ITEM dialog[]);    add an item to an open dialog
  11.  *  editbox_initialize(EDITBOX *edit);                              initialize an editbox with a new string
  12.  *  listbox_initialize(LISTBOX *list);                              initialize a listbox with a new list
  13.  *  radiobutton_set(RADIOBUTTON *radio,short id);                   sets a particular radiobutton
  14.  *  checkbox_set(BUTTON *button,short id);                          sets a checkbox
  15.  *  checkbox_clear(BUTTON *button,short id);                        clears a checkbox
  16.  * system: Written for the flash graphics library in Zortech 3.0
  17.  * copyright: 1992 by David Weber.  All rights reserved.
  18.  *  This software can be used for any purpose as object, library or executable.
  19.  *  It cannot be sold for profit as source code.
  20.  * history:
  21.  *  01-01-92 - initial code
  22.  *  01-31-93 - this code is now obsolete, see the CPP gui package
  23.  **************************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include "gui.h"
  30.  
  31. /* local defines */
  32. #define FOCUS_CLEAR 0
  33. #define FOCUS_SET 1
  34.  
  35. /* local prototypes */
  36. static void dialog_focus_draw(DIALOG_ITEM *dialog,short type);
  37. static short dialog_refocus(DIALOG_ITEM dialog[],DIALOG_ITEM *item);
  38. static void dialog_focus_next(DIALOG_ITEM dialog[]);
  39. static void dialog_focus_previous(DIALOG_ITEM dialog[]);
  40. static short text_open(short x,short y,TEXT *text,fg_pbox_t area,DIALOG_ITEM *d);
  41. static short dialog_draw_text(short x,short y,char *str,fg_pbox_t clip);
  42. static short dialog_draw_gray_text(short x,short y,char *str,fg_pbox_t clip);
  43. static short button_open(short x,short y,BUTTON *button,fg_pbox_t area,DIALOG_ITEM *d);
  44. static short checkbox_open(short x,short y,BUTTON *button,fg_pbox_t area,DIALOG_ITEM *d);
  45. static void checkbox_draw(short x,short y,BUTTON *b,fg_pbox_t clip,fg_pbox_t focus);
  46. static void checkbox_draw_gray(short x,short y,BUTTON *b,fg_pbox_t clip,fg_pbox_t focus);
  47. static void checkbox_mark(BUTTON *b);
  48. static void checkbox_unmark(BUTTON *b);
  49. static short radiobutton_open(short x,short y,RADIOBUTTON *radio,fg_pbox_t area,DIALOG_ITEM *d);
  50. static void radiobutton_mark(BUTTON *b,DIALOG_ITEM *d);
  51. static void radiobutton_unmark(BUTTON *b);
  52. static BUTTON *radiobutton_unmark_all(BUTTON *first,short number_of_buttons);
  53. static BUTTON *radiobutton_previous(BUTTON *first,short number_of_buttons);
  54. static BUTTON *radiobutton_next(BUTTON *first,short number_of_buttons);
  55. static short listbox_open(short x,short y,LISTBOX *list,fg_pbox_t area,DIALOG_ITEM *d);
  56. static void listbox_close(LISTBOX *list);
  57. static void listbox_free(LISTBOX *list);
  58. static void listbox_draw_contents(LISTBOX *list);
  59. static short listbox_allocate_page(LISTBOX *list,short type);
  60. static void listbox_mark(LISTBOX *list);
  61. static short listbox_scroll(LISTBOX *list,short number_of_lines);
  62. static char *listbox_current_data(LISTBOX *list,short offset);
  63. static short editbox_open(short x,short y,EDITBOX *edit,fg_pbox_t area,DIALOG_ITEM *d);
  64. static void editbox_close(EDITBOX *edit);
  65. static void editbox_draw(EDITBOX *edit);
  66. static void editbox_cursor(EDITBOX *edit);
  67. static short editbox_edit(EDITBOX *edit,short key);
  68.  
  69.  
  70. /************************************************
  71.  * function: short dialog_open(DIALOG_ITEM dialog[],short number_of_items,short loc_x,short loc_y,short width,short height)
  72.  *  registers a dialog box, initializes all the hotspots and draws it
  73.  *  In this simple gui dialog boxes are always modal
  74.  * parameters: array of dialog items in dialog box, number of items in array,
  75.  *      location of box relative to lower left corner of screen in quarter text
  76.  *      cell units, width and height of box also in quarter text cell units.
  77.  *      If loc_x or loc_y is -1 then the box is centered in the screen
  78.  * returns: 1 if opened or 0 if failed because of lack of resources
  79.  ************************************************/
  80. short dialog_open(DIALOG_ITEM dialog[],short number_of_items,short loc_x,short loc_y,short width,short height)
  81.     {
  82.     short i,j,fail;
  83.     DIALOG_ITEM *d,*d2;
  84.     fg_box_t dialog_area;
  85.     MESSAGE error;
  86.  
  87.     i = 0;      /* verify parameters */
  88.     if (number_of_items < 0 || number_of_items > DIALOG_MAX_ITEMS)
  89.         i = 1;
  90.     else
  91.         for (j = 0 ; j < number_of_items ; j++)
  92.             {
  93.             d = &dialog[j];
  94.             if (d->type < DIALOG_MIN_TYPE || d->type > DIALOG_MAX_TYPE || d->data == NULL)
  95.                 i = 1;
  96.             }
  97.     if (i)
  98.         {
  99.         error.id = gui_errno = M_INVALID_PARMS;
  100.         error.data.ptr_data = dialog_open;
  101.         message_send(&error);
  102.         return 0;
  103.         }
  104.     fg_msm_hidecursor();
  105.     loc_x = (gui_char_width * loc_x) / DIALOG_UNITS;    /* screen units */
  106.     loc_y = (gui_char_height * loc_y) / DIALOG_UNITS;
  107.     width = (gui_char_width * width) / DIALOG_UNITS;
  108.     height = (gui_char_height * height) / DIALOG_UNITS;
  109.     if (loc_x < 0 || loc_y < 0)                     /* center it? */
  110.         {
  111.         loc_x = (fg.displaybox[FG_X2] - fg.displaybox[FG_X1])/2 - width/2;
  112.         if (loc_x < 0) loc_x = 0;
  113.         loc_y = (fg.displaybox[FG_Y2] - fg.displaybox[FG_Y1])/2 - height/2;
  114.         if (loc_y < 0) loc_y = 0;
  115.         }
  116.     loc_x += fg.displaybox[FG_X1];
  117.     loc_y += fg.displaybox[FG_Y1];
  118.     if (loc_x + width > fg.displaybox[FG_X2])   /* adjust box to fit screen */
  119.         {
  120.         loc_x = fg.displaybox[FG_X2] - width;
  121.         if (loc_x < 0)
  122.             loc_x = 0;
  123.         }
  124.     if (loc_y + height > fg.displaybox[FG_Y2])
  125.         {
  126.         loc_y = fg.displaybox[FG_Y2] - height;
  127.         if (loc_y < 0)
  128.             loc_y = 0;
  129.         }
  130.     dialog_area[FG_X1] = loc_x;                 /* coordinates of dialog box */
  131.     dialog_area[FG_X2] = loc_x + width;
  132.     dialog_area[FG_Y1] = loc_y;
  133.     dialog_area[FG_Y2] = loc_y + height;
  134.     fg_boxclip(fg.displaybox,dialog_area,dialog_area);
  135.     if (!object_add(OBJECT_DIALOG,(GENERIC_MESSAGE_HANDLER)dialog_message_handler,dialog,dialog_area))
  136.         {                                       /* add object to active list */
  137.         fg_msm_showcursor();
  138.         fg_flush();
  139.         return 0;
  140.         }
  141.     fg_fillbox(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,dialog_area);     /* draw box */
  142.     fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,dialog_area,fg.displaybox);
  143.     for (i=0, d2=NULL, fail=0 ; i < number_of_items ; i++)
  144.         {
  145.         d = &dialog[i];
  146.         d->dialog_state = DIALOG_FIXED;
  147.         switch (d->type)    /* set up hotspots and draw items */
  148.             {
  149.             case DIALOG_TEXT:
  150.                 fail = text_open(loc_x,loc_y,(TEXT *)d->data,dialog_area,d);
  151.                 break;
  152.             case DIALOG_BUTTON:
  153.                 fail = button_open(loc_x,loc_y,(BUTTON *)d->data,dialog_area,d);
  154.                 break;
  155.             case DIALOG_CHECKBOX:
  156.                 fail = checkbox_open(loc_x,loc_y,(BUTTON *)d->data,dialog_area,d);
  157.                 break;
  158.             case DIALOG_RADIOBUTTON:
  159.                 fail = radiobutton_open(loc_x,loc_y,(RADIOBUTTON *)d->data,dialog_area,d);
  160.                 break;
  161.             case DIALOG_LISTBOX:
  162.                 fail = listbox_open(loc_x,loc_y,(LISTBOX *)d->data,dialog_area,d);
  163.                 break;
  164.             case DIALOG_EDITBOX:
  165.                 fail = editbox_open(loc_x,loc_y,(EDITBOX *)d->data,dialog_area,d);
  166.                 break;
  167.             default:
  168.                 break;
  169.             }
  170.         d->next = NULL;     /* thread linked list */
  171.         if (d2 != NULL)
  172.             d2->next = d;
  173.         d2 = d;
  174.         if (fail)           /* handle errors */
  175.             {
  176.             if (fail != M_NULL_ERROR)   /* null error means error message was already sent */
  177.                 {
  178.                 error.id = gui_errno = fail;
  179.                 error.data.ptr_data = dialog_open;
  180.                 message_send(&error);
  181.                 }
  182.             dialog_close(dialog);
  183.             fg_msm_showcursor();
  184.             fg_flush();
  185.             return 0;
  186.             }
  187.         }
  188.     exclusive_focus_set(dialog);    /* force exclusive focus on dialog box */
  189.     d->dialog_state |= DIALOG_FOCUS_HERE;   /* local focus on first dialog item */
  190.     dialog_focus_next(dialog);
  191.     fg_msm_showcursor();
  192.     fg_flush();
  193.     return 1;
  194.     }
  195.  
  196.  
  197. /************************************************
  198.  * function: void dialog_message_handler(MESSAGE *message,DIALOG_ITEM *dialog)
  199.  *  handles messages for dialog boxes, the following transforms occur:
  200.  *      BUTTON - when selected the button id is returned as a message id
  201.  *      CHECKBOX - when selected the checkbox id is returned as a message id,
  202.  *                  message->data.short_data.x is 1 if box is on or 0 if off
  203.  *      RADIOBUTTON - when any button in the radio button set is selected the
  204.  *                  radio set id is returned as the message id, the id of the
  205.  *                  button in the set which was selected is returned as
  206.  *                  message->data.short_data.x and the button which was deselected
  207.  *                  is returned as message->data.short_data.y
  208.  *      LISTBOX - when any item displayed in a list box is selected with either
  209.  *                  the mouse or with the RETURN key, the listbox id is
  210.  *                  returned as the message id and a pointer to the string is
  211.  *                  returned as message->data.ptr_data
  212.  *      EDITBOX - If the RETURN key is hit while the editbox has the focus, the
  213.  *                  editbox id is returned as the message id and
  214.  *                  message->data.short_data.x is EDITBOX_ACCEPT.  If a change
  215.  *                  is made to the contents of an editbox, the editbox id is
  216.  *                  returned as the message id and message->data.short_data.x
  217.  *                  is EDITBOX_CHANGE
  218.  * parameters: pointer to message, pointer to object data
  219.  * returns: nothing
  220.  ************************************************/
  221. void dialog_message_handler(MESSAGE *message,DIALOG_ITEM *dialog)
  222.     {
  223.     DIALOG_ITEM *d;
  224.     BUTTON *b,*b2;
  225.     RADIOBUTTON *r;
  226.     LISTBOX *l;
  227.     EDITBOX *e;
  228.     char *p;
  229.     short i,key,x,y,focus;
  230.  
  231.     switch (message->id)
  232.         {
  233.         case M_KEY:                 /*** KEY MESSAGE ***/
  234.             key = message->data.short_data.x;
  235.             if (key == TAB)         /* focus on next */
  236.                 {
  237.                 dialog_focus_next(dialog);
  238.                 message->id = M_NONE;
  239.                 return;
  240.                 }
  241.             if (key == SHIFTTAB)    /* focus on previous */
  242.                 {
  243.                 dialog_focus_previous(dialog);
  244.                 message->id = M_NONE;
  245.                 return;
  246.                 }
  247.             for (d = dialog ; d != NULL ; d = d->next)
  248.                 {
  249.                 if (d->dialog_state & DIALOG_FOCUS_HERE)    /* does this one have the focus? */
  250.                     focus = 1;
  251.                 else
  252.                     focus = 0;
  253.                 switch (d->type)
  254.                     {
  255.                     case DIALOG_CHECKBOX:
  256.                         b = (BUTTON *) d->data;
  257.                         if (is_active(*b))
  258.                             if (b->accelerator == key || ((key == RETURN || key == SPACE) && focus))
  259.                                 {
  260.                                 if (is_selected(*b))
  261.                                     {
  262.                                     checkbox_unmark(b);
  263.                                     message->data.short_data.x = 0;
  264.                                     }
  265.                                 else
  266.                                     {
  267.                                     checkbox_mark(b);
  268.                                     message->data.short_data.x = 1;
  269.                                     }
  270.                                 dialog_refocus(dialog,d);
  271.                                 message->id = b->id;
  272.                                 return;
  273.                                 }
  274.                         break;
  275.                     case DIALOG_BUTTON:
  276.                         b = (BUTTON *) d->data;
  277.                         if (is_active(*b))
  278.                             if (b->accelerator == key || (key == RETURN && focus))
  279.                                 {
  280.                                 dialog_refocus(dialog,d);
  281.                                 message->id = b->id;
  282.                                 return;
  283.                                 }
  284.                         break;
  285.                     case DIALOG_RADIOBUTTON:
  286.                         r = (RADIOBUTTON *) d->data;
  287.                         if (is_active(*r))
  288.                             {
  289.                             for (i = 0, b = r->buttons ; i < r->number_of_buttons ; i++, b++)
  290.                                 if (is_active(*b))
  291.                                     if (b->accelerator == key || ((key == RETURN || key == SPACE || key == DOWNARROW || key == UPARROW || key == RIGHTARROW || key == LEFTARROW) && focus))
  292.                                         {
  293.                                         if (b->accelerator != key)
  294.                                             {
  295.                                             if (key == UPARROW || key == LEFTARROW)
  296.                                                 b = radiobutton_previous(r->buttons,r->number_of_buttons);
  297.                                             else
  298.                                                 b = radiobutton_next(r->buttons,r->number_of_buttons);
  299.                                             }
  300.                                         b2 = radiobutton_unmark_all(r->buttons,r->number_of_buttons);
  301.                                         dialog_refocus(dialog,d);
  302.                                         if (b2 == NULL)
  303.                                             message->data.short_data.y = 0;
  304.                                         else
  305.                                             message->data.short_data.y = b2->id;
  306.                                         message->data.short_data.x = b->id;
  307.                                         radiobutton_mark(b,d);
  308.                                         message->id = r->id;
  309.                                         return;
  310.                                         }
  311.                             }
  312.                         break;
  313.                     case DIALOG_LISTBOX:
  314.                         l = (LISTBOX *) d->data;
  315.                         if (is_active(*l) && focus)
  316.                             {
  317.                             i = 0;
  318.                             if (key == UPARROW) i = -1;
  319.                             if (key == DOWNARROW) i = 1;
  320.                             if (key == PGUP) i = -l->height/DIALOG_UNITS;
  321.                             if (key == PGDN) i = l->height/DIALOG_UNITS;
  322.                             if (key == CTRLPGUP || key == CTRLHOME) i = -10000;
  323.                             if (key == CTRLPGDN || key == CTRLEND) i = 10000;
  324.                             if (i)
  325.                                 {
  326.                                 listbox_scroll(l,i);
  327.                                 message->id = M_NONE;
  328.                                 return;
  329.                                 }
  330.                             if (key == RETURN)
  331.                                 {
  332.                                 if ((p = listbox_current_data(l,l->screen_offset)) == NULL)
  333.                                     break;
  334.                                 message->id = l->id;
  335.                                 message->data.ptr_data = p;
  336.                                 return;
  337.                                 }
  338.                             }
  339.                         break;
  340.                     case DIALOG_EDITBOX:
  341.                         e = (EDITBOX *) d->data;
  342.                         if (is_active(*e) && focus)
  343.                             {
  344.                             if (key == RETURN)
  345.                                 {
  346.                                 message->id = e->id;
  347.                                 message->data.short_data.x = 1;
  348.                                 return;
  349.                                 }
  350.                             i = editbox_edit(e,key);
  351.                             if (i == 2)
  352.                                 {
  353.                                 message->id = e->id;
  354.                                 message->data.short_data.x = 0;
  355.                                 return;
  356.                                 }
  357.                             if (i == 1)
  358.                                 {
  359.                                 message->id = M_NONE;
  360.                                 return;
  361.                                 }
  362.                             }
  363.                         break;
  364.                     default:
  365.                         break;
  366.                     }
  367.                 }
  368.             break;
  369.         case M_MOUSE_LEFT:          /*** MOUSE MESSAGE ***/
  370.         case M_MOUSE_CENTER:
  371.         case M_MOUSE_RIGHT:
  372.             x = message->data.short_data.x;
  373.             y = message->data.short_data.y;
  374.             for (d = dialog ; d != NULL ; d = d->next)
  375.                 {
  376.                 switch (d->type)
  377.                     {
  378.                     case DIALOG_BUTTON:
  379.                     case DIALOG_CHECKBOX:
  380.                         b = (BUTTON *) d->data;
  381.                         if (is_active(*b))
  382.                             {
  383.                             if (fg_pt_inbox(b->screen,x,y))
  384.                                 {                   /* dialog item selected */
  385.                                 dialog_refocus(dialog,d);
  386.                                 if (d->type == DIALOG_CHECKBOX) /* mark or unmark checkbox */
  387.                                     {
  388.                                     if (is_selected(*b))
  389.                                         {
  390.                                         checkbox_unmark(b);
  391.                                         message->data.short_data.x = 0;
  392.                                         }
  393.                                     else
  394.                                         {
  395.                                         checkbox_mark(b);
  396.                                         message->data.short_data.x = 1;
  397.                                         }
  398.                                     }
  399.                                 message->id = b->id;
  400.                                 return;
  401.                                 }
  402.                             }
  403.                         break;
  404.                     case DIALOG_RADIOBUTTON:
  405.                         r = (RADIOBUTTON *) d->data;
  406.                         if (is_active(*r))
  407.                             {
  408.                             for (i = 0, b = r->buttons ; i < r->number_of_buttons ; i++, b++)
  409.                                 if (fg_pt_inbox(b->screen,x,y) && is_active(*b))
  410.                                     {
  411.                                     dialog_refocus(dialog,d);
  412.                                     b2 = radiobutton_unmark_all(r->buttons,r->number_of_buttons);
  413.                                     if (b2 == NULL)
  414.                                         message->data.short_data.y = 0;
  415.                                     else
  416.                                         message->data.short_data.y = b2->id;
  417.                                     message->data.short_data.x = b->id;
  418.                                     radiobutton_mark(b,d);
  419.                                     message->id = r->id;
  420.                                     return;
  421.                                     }
  422.                             }
  423.                         break;
  424.                     case DIALOG_LISTBOX:
  425.                         l = (LISTBOX *) d->data;
  426.                         if (is_active(*l))
  427.                             {
  428.                             if (fg_pt_inbox(l->screen,x,y))
  429.                                 dialog_refocus(dialog,d);
  430.                             i = 0;
  431.                             if (fg_pt_inbox(l->up,x,y))
  432.                                 i = -l->height/DIALOG_UNITS;
  433.                             if (fg_pt_inbox(l->down,x,y))
  434.                                 i = l->height/DIALOG_UNITS;
  435.                             if (i)
  436.                                 {
  437.                                 listbox_scroll(l,i);
  438.                                 message->id = M_NONE;
  439.                                 return;
  440.                                 }
  441.                             if (fg_pt_inbox(l->listbox,x,y))
  442.                                 {
  443.                                 i = (l->listbox[FG_Y2]-y)/gui_char_height;
  444.                                 if ((p = listbox_current_data(l,i)) == NULL)
  445.                                     break;
  446.                                 l->screen_offset = i;
  447.                                 listbox_mark(l);
  448.                                 message->id = l->id;
  449.                                 message->data.ptr_data = p;
  450.                                 return;
  451.                                 }
  452.                             if (fg_pt_inbox(l->marker,x,y))
  453.                                 {
  454.                                 i = (l->listbox[FG_Y2]-y)/gui_char_height;
  455.                                 if ((p = listbox_current_data(l,i)) == NULL)
  456.                                     break;
  457.                                 l->screen_offset = i;
  458.                                 listbox_mark(l);
  459.                                 message->id = M_NONE;
  460.                                 return;
  461.                                 }
  462.                             }
  463.                         break;
  464.                     case DIALOG_EDITBOX:
  465.                         e = (EDITBOX *) d->data;
  466.                         if (is_active(*e))
  467.                             {
  468.                             if (fg_pt_inbox(e->screen,x,y))
  469.                                 {
  470.                                 dialog_refocus(dialog,d);
  471.                                 i = (x - e->screen[FG_X1] - 1)/gui_char_width;
  472.                                 if (i >= e->screen_width/DIALOG_UNITS)
  473.                                     i = e->screen_width/DIALOG_UNITS - 1;
  474.                                 e->xpos = e->scroll_offset + i;
  475.                                 p = e->edit_string;
  476.                                 i = e->xpos;
  477.                                 if (i >= strlen(p))
  478.                                     {
  479.                                     memset(p+strlen(p),' ',i-strlen(p)+1);
  480.                                     p[i+1] = 0;
  481.                                     }
  482.                                 editbox_cursor(e);
  483.                                 message->id = M_NONE;
  484.                                 return;
  485.                                 }
  486.                             }
  487.                         break;
  488.                     default:
  489.                         break;
  490.                     }
  491.                 }
  492.             break;
  493.         default:
  494.             return;
  495.         }
  496.     }
  497.  
  498.  
  499. /************************************************
  500.  * function: short dialog_close(DIALOG_ITEM dialog[])
  501.  * parameters: pointer to previously opened dialog box
  502.  * returns: 1 if OK or 0 if failed
  503.  ************************************************/
  504. short dialog_close(DIALOG_ITEM dialog[])
  505.     {
  506.     short ret;
  507.     DIALOG_ITEM *d,*d2;
  508.  
  509.     fg_msm_hidecursor();
  510.     exclusive_focus_clear(dialog);      /* remove focus restriction */
  511.     if ((ret = object_remove(dialog)) != 0)
  512.         for (d = dialog ; d != NULL ; d = d2)
  513.             {
  514.             if (d->type == DIALOG_CHECKBOX)
  515.                 ((BUTTON *) d->data)->status &= ~DIALOG_OPENED;
  516.             if (d->type == DIALOG_RADIOBUTTON)
  517.                 ((RADIOBUTTON *) d->data)->status &= ~DIALOG_OPENED;
  518.             if (d->type == DIALOG_LISTBOX)
  519.                 listbox_close((LISTBOX *) d->data);
  520.             if (d->type == DIALOG_EDITBOX)
  521.                 editbox_close((EDITBOX *) d->data);
  522.             d2 = d->next;
  523.             if (d->dialog_state == DIALOG_ALLOCATED)
  524.                 free(d);
  525.             }
  526.     fg_msm_showcursor();
  527.     fg_flush();
  528.     return ret;
  529.     }
  530.  
  531.  
  532. /************************************************
  533.  * function: short dialog_add_item(short type,void *data,DIALOG_ITEM dialog[])
  534.  * parameters: type of item, item's data, opened dialog box
  535.  * returns: 1 if added or 0 if failed
  536.  ************************************************/
  537. short dialog_add_item(short type,void *data,DIALOG_ITEM dialog[])
  538.     {
  539.     short fail,x,y;
  540.     GOB *o;
  541.     DIALOG_ITEM *d,*d2;
  542.     MESSAGE error;
  543.  
  544.     if (type < DIALOG_MIN_TYPE || type > DIALOG_MAX_TYPE || data == NULL)
  545.         {       /* is it proper? */
  546.         error.id = gui_errno = M_INVALID_PARMS;
  547.         error.data.ptr_data = dialog_add_item;
  548.         message_send(&error);
  549.         return 0;
  550.         }
  551.     if ((o = object_exists(dialog)) == NULL)
  552.         {       /* is it there? */
  553.         error.id = gui_errno = M_NOT_OPEN;
  554.         error.data.ptr_data = dialog_add_item;
  555.         message_send(&error);
  556.         return 0;
  557.         }
  558.     if ((d = (DIALOG_ITEM *) malloc(sizeof (DIALOG_ITEM))) == NULL)
  559.         {       /* are there resources? */
  560.         error.id = gui_errno = M_NOMEM;
  561.         error.data.ptr_data = dialog_add_item;
  562.         message_send(&error);
  563.         return 0;
  564.         }
  565.     d->dialog_state = DIALOG_ALLOCATED;     /* build DIALOG_ITEM */
  566.     d->type = type;
  567.     d->data = data;
  568.     d->next = NULL;
  569.     fail = 0;
  570.     x = o->screen[FG_X1];
  571.     y = o->screen[FG_Y1];
  572.     fg_msm_hidecursor();
  573.     switch (type)       /* set up hotspots and draw items */
  574.         {
  575.         case DIALOG_TEXT:
  576.             fail = text_open(x,y,(TEXT *)data,o->screen,d);
  577.             break;
  578.         case DIALOG_BUTTON:
  579.             fail = button_open(x,y,(BUTTON *)data,o->screen,d);
  580.             break;
  581.         case DIALOG_CHECKBOX:
  582.             fail = checkbox_open(x,y,(BUTTON *)data,o->screen,d);
  583.             break;
  584.         case DIALOG_RADIOBUTTON:
  585.             fail = radiobutton_open(x,y,(RADIOBUTTON *)data,o->screen,d);
  586.             break;
  587.         case DIALOG_LISTBOX:
  588.             fail = listbox_open(x,y,(LISTBOX *)data,o->screen,d);
  589.             break;
  590.         case DIALOG_EDITBOX:
  591.             fail = editbox_open(x,y,(EDITBOX *)data,o->screen,d);
  592.             break;
  593.         default:
  594.             break;
  595.         }
  596.     fg_msm_showcursor();
  597.     fg_flush();
  598.     if (fail)
  599.         {       /* is it platable? */
  600.         free(d);
  601.         error.id = gui_errno = fail;
  602.         error.data.ptr_data = dialog_add_item;
  603.         message_send(&error);
  604.         return 0;
  605.         }
  606.     for (d2 = dialog ; d2->next != NULL ; d2 = d2->next)
  607.         ;
  608.         /* thread it on the end */
  609.     d2->next = d;
  610.     return 1;
  611.     }
  612.  
  613.  
  614. /************************************************
  615.  * function: short editbox_initialize(EDITBOX *edit)
  616.  *  redraw the editbox with a new string,  call this after you change the
  617.  *  string in the editbox structure
  618.  * parameters: pointer to opened editbox
  619.  * returns: 1 if OK or 0 if failed
  620.  ************************************************/
  621. short editbox_initialize(EDITBOX *edit)
  622.     {
  623.     MESSAGE error;
  624.  
  625.     if ((edit->status & DIALOG_OPENED) == 0)
  626.         {   /* cannot initialize an unopened box */
  627.         error.id = gui_errno = M_NOT_OPEN;
  628.         error.data.ptr_data = editbox_initialize;
  629.         message_send(&error);
  630.         return 0;
  631.         }
  632.     edit->scroll_offset = edit->xpos = edit->insert = edit->curtype = edit->curpos = 0;
  633.     editbox_draw(edit);
  634.     return 1;
  635.     }
  636.  
  637.  
  638. /************************************************
  639.  * function: short listbox_initialize(LISTBOX *list)
  640.  *  clear listbox and redraw contents, call this if you change the
  641.  *  first_item next_item functions in the list data structure
  642.  * parameters: pointer to listbox
  643.  * returns: 1 if OK or 0 if failed
  644.  ************************************************/
  645. short listbox_initialize(LISTBOX *list)
  646.     {
  647.     MESSAGE error;
  648.  
  649.     if ((list->status & DIALOG_OPENED) == 0)
  650.         {   /* cannot initialize an unopened box */
  651.         error.id = gui_errno = M_NOT_OPEN;
  652.         error.data.ptr_data = listbox_initialize;
  653.         message_send(&error);
  654.         return 0;
  655.         }
  656.     list->status &= ~DIALOG_COMPLETED;
  657.     if (list->first_page != NULL)       /* clean up old pages */
  658.         listbox_free(list);
  659.     if (!listbox_allocate_page(list,LISTBOX_FIRST_PAGE))    /* get first page */
  660.         return 0;
  661.     listbox_draw_contents(list);        /* display it */
  662.     listbox_mark(list);             /* display marker */
  663.     return 1;
  664.     }
  665.  
  666.  
  667. /************************************************
  668.  * function: short radiobutton_set(RADIOBUTTON *radio,short id)
  669.  *  set a button in a radiobutton set using the unique id associated with a
  670.  *  button to identify it.
  671.  * parameters: radio button, unique id of button in radiobutton to set
  672.  * returns: 1 if set or 0 if not
  673.  ************************************************/
  674. short radiobutton_set(RADIOBUTTON *radio,short id)
  675.     {
  676.     BUTTON *old,*new,*b;
  677.     short i;
  678.  
  679.     for (i = 0, b = radio->buttons, old = new = NULL ; i < radio->number_of_buttons ; i++, b++)
  680.         {
  681.         if (b->id == id)
  682.             new = b;
  683.         if (is_selected(*b))
  684.             old = b;
  685.         }
  686.     if (new == NULL || is_inactive(*new))
  687.         return 0;
  688.     if (radio->status & DIALOG_OPENED)
  689.         {
  690.         radiobutton_unmark_all(radio->buttons,radio->number_of_buttons);
  691.         radiobutton_mark(new,radio->dialog);
  692.         }
  693.     else
  694.         {
  695.         if (old != NULL)
  696.             old->status &= ~DIALOG_SELECTED;
  697.         new->status |= DIALOG_SELECTED;
  698.         }
  699.     return 1;
  700.     }
  701.  
  702.  
  703. /************************************************
  704.  * function: short checkbox_set(BUTTON *button,short id)
  705.  *  set a checkbox to on
  706.  * parameters: checkbox button to set and the unique id of the button
  707.  * returns: 1 if set or 0 if not
  708.  ************************************************/
  709. short checkbox_set(BUTTON *button,short id)
  710.     {
  711.     if (button->id != id)
  712.         return 0;
  713.     if (button->status & DIALOG_OPENED)
  714.         checkbox_mark(button);
  715.     else
  716.         button->status |= DIALOG_SELECTED;
  717.     return 1;
  718.     }
  719.  
  720.  
  721. /************************************************
  722.  * function: short checkbox_clear(BUTTON *button,short id)
  723.  *  set a checkbox to off
  724.  * parameters: checkbox button to clear and the unique id of the button
  725.  * returns: 1 if set or 0 if not
  726.  ************************************************/
  727. short checkbox_clear(BUTTON *button,short id)
  728.     {
  729.     if (button->id != id)
  730.         return 0;
  731.     if (button->status & DIALOG_OPENED)
  732.         checkbox_unmark(button);
  733.     else
  734.         button->status &= ~DIALOG_SELECTED;
  735.     return 1;
  736.     }
  737.  
  738.  
  739. /* ---------------- LOCAL FUNCTIONS ---------------- */
  740.  
  741. /* draw a dialog focus, type is FOCUS_CLEAR or FOCUS_SET */
  742. static void dialog_focus_draw(DIALOG_ITEM *dialog,short type)
  743.     {
  744.     short color1,color2;
  745.     fg_box_t box;
  746.  
  747.     if (type == FOCUS_SET)
  748.         color1 = color2 = COLOR_DIALOG_FOCUS;
  749.     else
  750.         {
  751.         color1 = COLOR_DIALOG_FOREGROUND;
  752.         color2 = COLOR_DIALOG_BACKGROUND;
  753.         }
  754.     fg_msm_hidecursor();
  755.     fg_box_cpy(box,dialog->focus);
  756.     fg_drawbox(color1,FG_MODE_SET,~0,FG_LINE_SOLID,box,fg.displaybox);
  757.     box[FG_X1]--;
  758.     box[FG_Y1]--;
  759.     box[FG_X2]++;
  760.     box[FG_Y2]++;
  761.     fg_drawbox(color2,FG_MODE_SET,~0,FG_LINE_SOLID,box,fg.displaybox);
  762.     fg_msm_showcursor();
  763.     fg_flush();
  764.     }
  765.  
  766.  
  767. /* clear all dialog foci and refocus on item */
  768. static short dialog_refocus(DIALOG_ITEM dialog[],DIALOG_ITEM *item)
  769.     {
  770.     DIALOG_ITEM *d;
  771.  
  772.     if (item->dialog_state & DIALOG_FOCUS_SKIP)     /* skip it? */
  773.         return 0;
  774.     for (d = dialog ; d != NULL ; d = d->next)      /* clear all foci */
  775.         if (d->dialog_state & DIALOG_FOCUS_HERE)
  776.             {
  777.             dialog_focus_draw(d,FOCUS_CLEAR);
  778.             d->dialog_state &= ~DIALOG_FOCUS_HERE;
  779.             }
  780.     dialog_focus_draw(item,FOCUS_SET);              /* set new focus */
  781.     item->dialog_state |= DIALOG_FOCUS_HERE;
  782.     return 1;
  783.     }
  784.  
  785.  
  786. /* focus on the next dialog object */
  787. static void dialog_focus_next(DIALOG_ITEM dialog[])
  788.     {
  789.     DIALOG_ITEM *current,*mark;
  790.  
  791.     for (current = dialog ; current != NULL ; current = current->next)
  792.         if (current->dialog_state & DIALOG_FOCUS_HERE)  /* find focus */
  793.             break;
  794.     if (current == NULL)
  795.         current = dialog;
  796.     mark = current;
  797.     do                              /* find next */
  798.         {
  799.         if (current->next == NULL)
  800.             current = dialog;
  801.         else
  802.             current = current->next;
  803.         if (current == mark)
  804.             break;
  805.         } while (current->dialog_state & DIALOG_FOCUS_SKIP);
  806.     dialog_refocus(dialog,current);
  807.     }
  808.  
  809.  
  810. /* focus on the previous dialog object */
  811. static void dialog_focus_previous(DIALOG_ITEM dialog[])
  812.     {
  813.     DIALOG_ITEM *d,*current,*mark;
  814.  
  815.     for (current = dialog ; current != NULL ; current = current->next)
  816.         if (current->dialog_state & DIALOG_FOCUS_HERE)  /* find focus */
  817.             break;
  818.     if (current == NULL)
  819.         current = dialog;
  820.     mark = current;
  821.     do                          /* find previous */
  822.         {
  823.         for (d = dialog ; d->next != current && d->next != NULL ; d = d->next)
  824.             ;
  825.         current = d;
  826.         if (current == mark)
  827.             break;
  828.         } while (current->dialog_state & DIALOG_FOCUS_SKIP);
  829.     dialog_refocus(dialog,current);
  830.     }
  831.  
  832.  
  833. /* ---------------- TEXT ---------------- */
  834.  
  835. /* verify parameters and draw text, returns 0 if OK else returns error message */
  836. static short text_open(short x,short y,TEXT *text,fg_pbox_t area,DIALOG_ITEM *d)
  837.     {
  838.     if (text->loc_x < 0 || text->loc_y < 0 || text->name == NULL || (text->status & ~DIALOG_BITS))
  839.         return M_INVALID_PARMS;
  840.     d->focus[FG_X1] = x+(gui_char_width*text->loc_x)/DIALOG_UNITS;
  841.     d->focus[FG_Y1] = y+(gui_char_height*text->loc_y)/DIALOG_UNITS;
  842.     if (is_gray(*text))
  843.         d->focus[FG_X2] = dialog_draw_gray_text(d->focus[FG_X1],d->focus[FG_Y1],text->name,area);
  844.     if (is_active(*text))
  845.         d->focus[FG_X2] = dialog_draw_text(d->focus[FG_X1],d->focus[FG_Y1],text->name,area);
  846.     d->focus[FG_Y2] = d->focus[FG_Y1] + gui_char_height;
  847.     d->dialog_state |= DIALOG_FOCUS_SKIP;
  848.     return 0;
  849.     }
  850.  
  851.  
  852. /* draw dialog text str at coordinates x,y using '&' highlighting, return new x value */
  853. static short dialog_draw_text(short x,short y,char *str,fg_pbox_t clip)
  854.     {
  855.     short i,color;
  856.  
  857.     for (i = 0 ; str[i] != 0 ; i++)
  858.         {
  859.         color = COLOR_DIALOG_FOREGROUND;
  860.         if (str[i] == '&')
  861.             {
  862.             i++;
  863.             if (str[i] == 0)
  864.                 i--;
  865.             if (str[i] != '&')
  866.                 color = COLOR_DIALOG_HIGHLIGHT;
  867.             }
  868.         fg_putc(color,FG_MODE_SET,~0,FG_ROT0,x,y,str[i],clip);
  869.         x += gui_char_width;
  870.         }
  871.     return x;
  872.     }
  873.  
  874.  
  875. /* draw gray dialog text str at coordinates x,y; return new x value */
  876. static short dialog_draw_gray_text(short x,short y,char *str,fg_pbox_t clip)
  877.     {
  878.     short i;
  879.  
  880.     for (i = 0 ; str[i] != 0 ; i++)
  881.         {
  882.         if (str[i] == '&')
  883.             {
  884.             i++;
  885.             if (str[i] == 0)
  886.                 i--;
  887.             }
  888.         fg_putc(COLOR_DIALOG_GRAY,FG_MODE_SET,~0,FG_ROT0,x,y,str[i],clip);
  889.         x += gui_char_width;
  890.         }
  891.     return x;
  892.     }
  893.  
  894.  
  895. /* ---------------- BUTTON ---------------- */
  896.  
  897. /* verify parameters and draw button, returns 0 if OK else returns error message */
  898. static short button_open(short x,short y,BUTTON *button,fg_pbox_t area,DIALOG_ITEM *d)
  899.     {
  900.     short cell_height,color;
  901.     fg_box_t temp;
  902.  
  903.     if (button->name == NULL || (button->status & ~DIALOG_BITS) ||
  904.         button->accelerator < KEY_MIN || button->accelerator > KEY_MAX)
  905.         return M_INVALID_PARMS;
  906.     if (is_active(*button) || is_gray(*button))
  907.         {
  908.         cell_height = gui_char_height + 6;
  909.         if (gui_char_height + gui_char_height/2 > cell_height)
  910.             cell_height = gui_char_height + gui_char_height/2;
  911.         temp[FG_X1] = x+(gui_char_width*button->loc_x)/DIALOG_UNITS;
  912.         temp[FG_Y1] = y+(gui_char_height*button->loc_y)/DIALOG_UNITS;
  913.         if (is_gray(*button))
  914.             {
  915.             temp[FG_X2] = dialog_draw_gray_text(temp[FG_X1],temp[FG_Y1],button->name,area);
  916.             color = COLOR_DIALOG_GRAY;
  917.             d->dialog_state |= DIALOG_FOCUS_SKIP;
  918.             }
  919.         else
  920.             {
  921.             temp[FG_X2] = dialog_draw_text(temp[FG_X1],temp[FG_Y1],button->name,area);
  922.             color = COLOR_DIALOG_FOREGROUND;
  923.             }
  924.         temp[FG_X1] -= gui_char_width;
  925.         temp[FG_X2] += gui_char_width;
  926.         temp[FG_Y1] -= (cell_height-gui_char_height)/2;
  927.         temp[FG_Y2] = temp[FG_Y1] + cell_height;
  928.         fg_drawbox(color,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  929.         fg_box_cpy(button->screen,temp);
  930.         fg_box_cpy(d->focus,temp);
  931.         }
  932.     else
  933.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  934.     return 0;
  935.     }
  936.  
  937.  
  938. /* ---------------- CHECKBOXES ---------------- */
  939.  
  940. /* verify parameters and draw button, returns 0 if OK else returns error message */
  941. static short checkbox_open(short x,short y,BUTTON *button,fg_pbox_t area,DIALOG_ITEM *d)
  942.     {
  943.     if (button->name == NULL || (button->status & ~DIALOG_BITS) ||
  944.         button->accelerator < KEY_MIN || button->accelerator > KEY_MAX)
  945.         return M_INVALID_PARMS;
  946.     if (is_gray(*button))
  947.         {
  948.         checkbox_draw_gray(x,y,button,area,d->focus);
  949.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  950.         }
  951.     else if (is_active(*button))
  952.         {
  953.         checkbox_draw(x,y,button,area,d->focus);
  954.         if (is_selected(*button))
  955.             checkbox_mark(button);
  956.         button->status |= DIALOG_OPENED;
  957.         }
  958.     else
  959.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  960.     return 0;
  961.     }
  962.  
  963.  
  964. /* draw a checkbox and fill the hotspot info */
  965. static void checkbox_draw(short x,short y,BUTTON *b,fg_pbox_t clip,fg_pbox_t focus)
  966.     {
  967.     fg_box_t temp;
  968.  
  969.     temp[FG_X1] = x + (gui_char_width*b->loc_x)/DIALOG_UNITS;
  970.     temp[FG_Y1] = y + (gui_char_height*b->loc_y)/DIALOG_UNITS;
  971.     temp[FG_X2] = dialog_draw_text(temp[FG_X1],temp[FG_Y1],b->name,clip);
  972.     temp[FG_X1] -= 2*gui_char_width;
  973.     temp[FG_Y2] = temp[FG_Y1] + gui_char_height;
  974.     fg_box_cpy(b->screen,temp);
  975.     temp[FG_X2] = temp[FG_X1] + gui_char_width;
  976.     temp[FG_Y1]++;
  977.     temp[FG_Y2]--;
  978.     fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,clip);
  979.     fg_box_cpy(focus,temp);
  980.     }
  981.  
  982.  
  983. /* draw a gray checkbox */
  984. static void checkbox_draw_gray(short x,short y,BUTTON *b,fg_pbox_t clip,fg_pbox_t focus)
  985.     {
  986.     fg_box_t temp;
  987.  
  988.     temp[FG_X1] = x + (gui_char_width*b->loc_x)/DIALOG_UNITS;
  989.     temp[FG_Y1] = y + (gui_char_height*b->loc_y)/DIALOG_UNITS;
  990.     temp[FG_X2] = dialog_draw_gray_text(temp[FG_X1],temp[FG_Y1],b->name,clip);
  991.     temp[FG_X1] -= 2*gui_char_width;
  992.     temp[FG_Y2] = temp[FG_Y1] + gui_char_height;
  993.     fg_box_cpy(b->screen,temp);
  994.     temp[FG_X2] = temp[FG_X1] + gui_char_width;
  995.     temp[FG_Y1]++;
  996.     temp[FG_Y2]--;
  997.     fg_drawbox(COLOR_DIALOG_GRAY,FG_MODE_SET,~0,FG_LINE_SOLID,temp,clip);
  998.     fg_box_cpy(focus,temp);
  999.     }
  1000.  
  1001.  
  1002. /* mark a check box by drawing an X and setting it selected */
  1003. static void checkbox_mark(BUTTON *b)
  1004.     {
  1005.     fg_line_t line;
  1006.     fg_box_t clip;
  1007.  
  1008.     fg_msm_hidecursor();
  1009.     clip[FG_X1] = b->screen[FG_X1]+1;
  1010.     clip[FG_Y1] = b->screen[FG_Y1]+2;
  1011.     clip[FG_X2] = b->screen[FG_X1]+gui_char_width-1;
  1012.     clip[FG_Y2] = b->screen[FG_Y2]-2;
  1013.     line[FG_X1] = clip[FG_X1];
  1014.     line[FG_Y1] = clip[FG_Y1];
  1015.     line[FG_X2] = clip[FG_X2];
  1016.     line[FG_Y2] = clip[FG_Y2];
  1017.     fg_drawlineclip(COLOR_DIALOG_SELECTION,FG_MODE_SET,~0,FG_LINE_SOLID,line,clip);
  1018.     line[FG_X1] = clip[FG_X1];
  1019.     line[FG_Y1] = clip[FG_Y2];
  1020.     line[FG_X2] = clip[FG_X2];
  1021.     line[FG_Y2] = clip[FG_Y1];
  1022.     fg_drawlineclip(COLOR_DIALOG_SELECTION,FG_MODE_SET,~0,FG_LINE_SOLID,line,clip);
  1023.     b->status |= DIALOG_SELECTED;
  1024.     fg_msm_showcursor();
  1025.     fg_flush();
  1026.     }
  1027.  
  1028.  
  1029. /* unmark a check box by clearing the X and setting it not selected */
  1030. static void checkbox_unmark(BUTTON *b)
  1031.     {
  1032.     fg_line_t line;
  1033.     fg_box_t clip;
  1034.  
  1035.     fg_msm_hidecursor();
  1036.     clip[FG_X1] = b->screen[FG_X1]+1;
  1037.     clip[FG_Y1] = b->screen[FG_Y1]+2;
  1038.     clip[FG_X2] = b->screen[FG_X1]+gui_char_width-1;
  1039.     clip[FG_Y2] = b->screen[FG_Y2]-2;
  1040.     line[FG_X1] = clip[FG_X1];
  1041.     line[FG_Y1] = clip[FG_Y1];
  1042.     line[FG_X2] = clip[FG_X2];
  1043.     line[FG_Y2] = clip[FG_Y2];
  1044.     fg_drawlineclip(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,line,clip);
  1045.     line[FG_X1] = clip[FG_X1];
  1046.     line[FG_Y1] = clip[FG_Y2];
  1047.     line[FG_X2] = clip[FG_X2];
  1048.     line[FG_Y2] = clip[FG_Y1];
  1049.     fg_drawlineclip(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,line,clip);
  1050.     b->status &= ~DIALOG_SELECTED;
  1051.     fg_msm_showcursor();
  1052.     fg_flush();
  1053.     }
  1054.  
  1055.  
  1056. /* ---------------- RADIOBUTTONS ---------------- */
  1057.  
  1058. /* verify parameters and draw buttons, returns 0 if OK else returns error message */
  1059. static short radiobutton_open(short x,short y,RADIOBUTTON *radio,fg_pbox_t area,DIALOG_ITEM *d)
  1060.     {
  1061.     short i;
  1062.     BUTTON *b;
  1063.     fg_box_t box;
  1064.  
  1065.     if (radio->number_of_buttons < 0 || radio->number_of_buttons > DIALOG_MAX_ITEMS || (radio->status & ~DIALOG_BITS))
  1066.         return M_INVALID_PARMS;
  1067.     for (i = 0 ; i < radio->number_of_buttons ; i++)
  1068.         {
  1069.         b = &(radio->buttons[i]);
  1070.         if (b->name == NULL || (b->status & ~DIALOG_BITS) ||
  1071.             b->accelerator < KEY_MIN || b->accelerator > KEY_MAX)
  1072.             return M_INVALID_PARMS;
  1073.         }
  1074.     if (is_active(*radio))
  1075.         {
  1076.         d->focus[FG_X1] = box[FG_X1] = -999;
  1077.         for (i = 0 ; i < radio->number_of_buttons ; i++)
  1078.             {
  1079.             b = &(radio->buttons[i]);
  1080.             if (is_gray(*b))
  1081.                 checkbox_draw_gray(x,y,b,area,box);
  1082.             if (is_active(*b))
  1083.                 {
  1084.                 checkbox_draw(x,y,b,area,box);
  1085.                 if (is_selected(*b))
  1086.                     {
  1087.                     radiobutton_mark(b,NULL);
  1088.                     fg_box_cpy(d->focus,box);
  1089.                     }
  1090.                 }
  1091.             }
  1092.         if (d->focus[FG_X1] == -999)        /* nothing selected, focus on last or skip */
  1093.             if (box[FG_X1] == -999)
  1094.                 d->dialog_state |= DIALOG_FOCUS_SKIP;
  1095.             else
  1096.                 fg_box_cpy(d->focus,box);
  1097.         radio->status |= DIALOG_OPENED;
  1098.         radio->dialog = d;
  1099.         }
  1100.     else
  1101.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  1102.     return 0;
  1103.     }
  1104.  
  1105.  
  1106. /* mark a radio button as on and set it as selected, also set focus */
  1107. static void radiobutton_mark(BUTTON *b,DIALOG_ITEM *d)
  1108.     {
  1109.     fg_box_t box;
  1110.  
  1111.     fg_msm_hidecursor();
  1112.     box[FG_X1] = b->screen[FG_X1];
  1113.     box[FG_Y1] = b->screen[FG_Y1] + 1;
  1114.     box[FG_X2] = box[FG_X1] + gui_char_width;
  1115.     box[FG_Y2] = b->screen[FG_Y2] - 1;
  1116.     if (d != NULL)
  1117.         {
  1118.         if (d->dialog_state & DIALOG_FOCUS_HERE)
  1119.             {
  1120.             dialog_focus_draw(d,FOCUS_CLEAR);
  1121.             fg_box_cpy(d->focus,box);
  1122.             dialog_focus_draw(d,FOCUS_SET);
  1123.             }
  1124.         else
  1125.             fg_box_cpy(d->focus,box);
  1126.         }
  1127.     box[FG_X1] += 2;
  1128.     box[FG_Y1] += 2;
  1129.     box[FG_X2] -= 2;
  1130.     box[FG_Y2] -= 2;
  1131.     fg_boxclip(fg.displaybox,box,box);
  1132.     fg_fillbox(COLOR_DIALOG_SELECTION,FG_MODE_SET,~0,box);
  1133.     b->status |= DIALOG_SELECTED;
  1134.     fg_msm_showcursor();
  1135.     fg_flush();
  1136.     }
  1137.  
  1138.  
  1139. /* unmark a radio button as off and set it as not selected */
  1140. static void radiobutton_unmark(BUTTON *b)
  1141.     {
  1142.     fg_box_t box;
  1143.  
  1144.     fg_msm_hidecursor();
  1145.     box[FG_X1] = b->screen[FG_X1]+2;
  1146.     box[FG_Y1] = b->screen[FG_Y1]+3;
  1147.     box[FG_X2] = b->screen[FG_X1]+gui_char_width-2;
  1148.     box[FG_Y2] = b->screen[FG_Y2]-3;
  1149.     fg_boxclip(fg.displaybox,box,box);
  1150.     fg_fillbox(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,box);
  1151.     b->status &= ~DIALOG_SELECTED;
  1152.     fg_msm_showcursor();
  1153.     fg_flush();
  1154.     }
  1155.  
  1156.  
  1157. /* unmark any radio button which may be on and deselect it
  1158.  * enter with pointer to first button
  1159.  * returns a pointer to the unmarked button or NULL if none */
  1160. static BUTTON *radiobutton_unmark_all(BUTTON *first,short number_of_buttons)
  1161.     {
  1162.     BUTTON *b,*b2;
  1163.     short i;
  1164.  
  1165.     for (i = 0, b = first, b2 = NULL ; i < number_of_buttons ; i++, b++)
  1166.         if (is_selected(*b))
  1167.             {
  1168.             radiobutton_unmark(b);
  1169.             b2 = b;
  1170.             }
  1171.     return b2;
  1172.     }
  1173.  
  1174.  
  1175. /* return the previous button in a radiobutton sequence */
  1176. static BUTTON *radiobutton_previous(BUTTON *first,short number_of_buttons)
  1177.     {
  1178.     short current,mark;
  1179.  
  1180.     for (current = 0 ; current < number_of_buttons ; current++)
  1181.         if (is_selected(*(first+current)))  /* find current */
  1182.             break;
  1183.     mark = current;
  1184.     do                                      /* find previous */
  1185.         {
  1186.         if (--current < 0)
  1187.             current = number_of_buttons-1;
  1188.         if (current == mark)
  1189.             break;
  1190.         } while (is_inactive(*(first+current)));
  1191.     return first+current;
  1192.     }
  1193.  
  1194.  
  1195. /* return the next button in a radiobutton sequence */
  1196. static BUTTON *radiobutton_next(BUTTON *first,short number_of_buttons)
  1197.     {
  1198.     short current,mark;
  1199.  
  1200.     for (current = 0 ; current < number_of_buttons ; current++)
  1201.         if (is_selected(*(first+current)))  /* find current */
  1202.             break;
  1203.     mark = current;
  1204.     do                                      /* find next */
  1205.         {
  1206.         if (++current >= number_of_buttons)
  1207.             current = 0;
  1208.         if (current == mark)
  1209.             break;
  1210.         } while (is_inactive(*(first+current)));
  1211.     return first+current;
  1212.     }
  1213.  
  1214.  
  1215. /* ---------------- LISTBOXES ---------------- */
  1216.  
  1217. /* verify parameters and open a listbox */
  1218. static short listbox_open(short x,short y,LISTBOX *list,fg_pbox_t area,DIALOG_ITEM *d)
  1219.     {
  1220.     fg_box_t temp;
  1221.  
  1222.     if (list->width < DIALOG_UNITS || list->height < DIALOG_UNITS ||
  1223.         list->first_item == NULL || list->next_item == NULL ||
  1224.         (list->status & ~DIALOG_BITS))
  1225.         return M_INVALID_PARMS;
  1226.     if (is_active(*list))
  1227.         {
  1228.         list->status &= ~DIALOG_COMPLETED;
  1229.         temp[FG_X1] = x+(gui_char_width*list->loc_x)/DIALOG_UNITS;
  1230.         temp[FG_Y1] = y+(gui_char_height*list->loc_y)/DIALOG_UNITS;
  1231.         temp[FG_X2] = temp[FG_X1]+gui_char_width*(list->width/DIALOG_UNITS+2)+5;
  1232.         temp[FG_Y2] = temp[FG_Y1]+gui_char_height*(list->height/DIALOG_UNITS)+1;
  1233.         fg_box_cpy(list->screen,temp);
  1234.         fg_box_cpy(d->focus,temp);
  1235.         fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  1236.         temp[FG_X2] = temp[FG_X1] + gui_char_width + 1;
  1237.         list->marker[FG_X1] = temp[FG_X1] + 1;
  1238.         list->marker[FG_Y1] = temp[FG_Y1] + 1;
  1239.         list->marker[FG_X2] = temp[FG_X2] - 1;
  1240.         list->marker[FG_Y2] = temp[FG_Y2] - 1;
  1241.         fg_boxclip(fg.displaybox,list->marker,list->marker);
  1242.         list->listbox[FG_X1] = temp[FG_X2] + 2;
  1243.         list->listbox[FG_Y1] = temp[FG_Y1] + 1;
  1244.         list->listbox[FG_Y2] = temp[FG_Y2] - 1;
  1245.         fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  1246.         temp[FG_X2] = list->screen[FG_X2];
  1247.         temp[FG_X1] = temp[FG_X2] - gui_char_width - 1;
  1248.         list->listbox[FG_X2] = temp[FG_X1] - 2;
  1249.         fg_boxclip(fg.displaybox,list->listbox,list->listbox);
  1250.         fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  1251.         temp[FG_Y2] = temp[FG_Y1] + (temp[FG_Y2] - temp[FG_Y1])/2;
  1252.         fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  1253.         fg_putc(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_ROT0,temp[FG_X1]+1,list->screen[FG_Y2]-gui_char_height-1,LIST_UPARROW,area);
  1254.         fg_putc(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_ROT0,temp[FG_X1]+1,list->screen[FG_Y1]+1,LIST_DOWNARROW,area);
  1255.         list->up[FG_X1] = list->down[FG_X1] = temp[FG_X1];
  1256.         list->up[FG_X2] = list->down[FG_X2] = temp[FG_X2];
  1257.         list->up[FG_Y1] = temp[FG_Y2] + 1;
  1258.         list->up[FG_Y2] = list->screen[FG_Y2];
  1259.         list->down[FG_Y1] = list->screen[FG_Y1];
  1260.         list->down[FG_Y2] = temp[FG_Y2];
  1261.         list->first_page = NULL;
  1262.         list->status |= DIALOG_OPENED;
  1263.         if (!listbox_initialize(list))
  1264.             return M_NULL_ERROR;
  1265.         }
  1266.     else
  1267.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  1268.     return 0;
  1269.     }
  1270.  
  1271.  
  1272. /* free allocated listbox pages and mark as unopened */
  1273. static void listbox_close(LISTBOX *list)
  1274.     {
  1275.     if (list->status & DIALOG_OPENED)
  1276.         {
  1277.         listbox_free(list);
  1278.         list->status &= ~(DIALOG_OPENED | DIALOG_COMPLETED);
  1279.         }
  1280.     }
  1281.  
  1282.  
  1283. /* free the pages allocated to the listbox */
  1284. static void listbox_free(LISTBOX *list)
  1285.     {
  1286.     LISTBOX_PAGE *lp,*lp2;
  1287.  
  1288.     lp = list->first_page;
  1289.     while (lp != NULL)
  1290.         {
  1291.         lp2 = lp->next_page;
  1292.         free(lp);
  1293.         lp = lp2;
  1294.         }
  1295.     list->first_page = NULL;
  1296.     }
  1297.  
  1298.  
  1299. /* erase the current list box and redraw using list->current_page and list->page_offset as the top of the list */
  1300. static void listbox_draw_contents(LISTBOX *list)
  1301.     {
  1302.     short x,y,box_height,string_size,page_offset;
  1303.     char *p;
  1304.     LISTBOX_PAGE *lp;
  1305.  
  1306.     fg_msm_hidecursor();
  1307.     fg_fillbox(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,list->listbox);   /* erase old list */
  1308.     string_size = list->width/DIALOG_UNITS + 1;     /* initialize variables */
  1309.     box_height = list->height/DIALOG_UNITS;
  1310.     lp = list->current_page;
  1311.     x = list->listbox[FG_X1];
  1312.     y = list->listbox[FG_Y2] - gui_char_height;
  1313.     page_offset = list->page_offset;
  1314.     p = lp->listbox_items + string_size * page_offset;
  1315.     while (box_height)
  1316.         {                       /* for each line in the box */
  1317.         if (page_offset >= lp->number_of_items)
  1318.             {                   /* if end of page, go to next page */
  1319.             if (lp->next_page == NULL)
  1320.                 {               /* next page not found, try to load it */
  1321.                 if (!listbox_allocate_page(list,LISTBOX_SUCCEEDING_PAGES))
  1322.                     {           /* fill next page */
  1323.                     fg_msm_showcursor();
  1324.                     fg_flush();
  1325.                     return;
  1326.                     }
  1327.                 if (list->status & DIALOG_COMPLETED)
  1328.                     break;      /* no more pages */
  1329.                 }
  1330.             lp = lp->next_page; /* adjust page pointers to next page */
  1331.             p = lp->listbox_items;
  1332.             page_offset = 0;
  1333.             }
  1334.         fg_puts(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_ROT0,x,y,p,list->listbox);
  1335.         box_height--;           /* adjust variables */
  1336.         page_offset++;
  1337.         y -= gui_char_height;
  1338.         p += string_size;
  1339.         }
  1340.     fg_msm_showcursor();
  1341.     fg_flush();
  1342.     }
  1343.  
  1344.  
  1345. /* allocate a new listbox page and fill it, returns pointer to page if OK or NULL if failed */
  1346. static short listbox_allocate_page(LISTBOX *list,short type)
  1347.     {
  1348.     short i,string_size;
  1349.     char *p;
  1350.     LISTBOX_PAGE *lp,*lp2;
  1351.     MESSAGE error;
  1352.  
  1353.     if (type == LISTBOX_SUCCEEDING_PAGES && (list->status & DIALOG_COMPLETED))
  1354.         return 1;                   /* list finished, no allocation needed */
  1355.     string_size = list->width/DIALOG_UNITS + 1;
  1356.     if ((lp = (LISTBOX_PAGE *) malloc(sizeof(LISTBOX_PAGE)+LISTBOX_MEM_PAGE_SIZE*string_size)) == NULL)
  1357.         {                           /* allocate page */
  1358.         error.id = gui_errno = M_NOMEM;
  1359.         error.data.ptr_data = listbox_allocate_page;
  1360.         message_send(&error);
  1361.         return 0;
  1362.         }
  1363.     lp->listbox_items = (char *) lp + sizeof(LISTBOX_PAGE); /* initialize page */
  1364.     lp->number_of_items = 0;
  1365.     if (type == LISTBOX_FIRST_PAGE)
  1366.         {                               /* first page is special */
  1367.         lp->previous_page = NULL;
  1368.         lp->next_page = NULL;
  1369.         if ((*(list->first_item))(lp->listbox_items))   /* fill first page */
  1370.             {
  1371.             for (i=lp->number_of_items=1, p=lp->listbox_items+string_size ; i < LISTBOX_MEM_PAGE_SIZE ; i++, p+=string_size)
  1372.                 {                               /* continue filling */
  1373.                 if ((*(list->next_item))(p))
  1374.                     lp->number_of_items++;
  1375.                 else
  1376.                     {
  1377.                     list->status |= DIALOG_COMPLETED;   /* list complete in this page */
  1378.                     break;
  1379.                     }
  1380.                 }
  1381.             }
  1382.         else
  1383.             list->status |= DIALOG_COMPLETED;       /* empty list */
  1384.         list->first_page = list->current_page = lp; /* preset list pointers and counters */
  1385.         list->page_offset = list->screen_offset = 0;
  1386.         }
  1387.     else if (type == LISTBOX_SUCCEEDING_PAGES)
  1388.         {
  1389.         for (lp2 = list->current_page ; lp2->next_page != NULL ; lp2 = lp2->next_page)
  1390.             ;       /* find end of list */
  1391.         lp2->next_page = lp;        /* thread page on to list */
  1392.         lp->next_page = NULL;
  1393.         lp->previous_page = lp2;
  1394.         for (i=0, p=lp->listbox_items ; i < LISTBOX_MEM_PAGE_SIZE ; i++, p+=string_size)
  1395.             {                       /* fill page */
  1396.             if ((*(list->next_item))(p))
  1397.                 lp->number_of_items++;
  1398.             else
  1399.                 {
  1400.                 list->status |= DIALOG_COMPLETED;   /* list complete in this page */
  1401.                 if (lp->number_of_items == 0)
  1402.                     {               /* nothing to put in this page */
  1403.                     lp2->next_page = NULL;
  1404.                     free(lp);
  1405.                     }
  1406.                 break;
  1407.                 }
  1408.             }
  1409.         }
  1410.     else            /* illegal type specifier */
  1411.         {
  1412.         free(lp);
  1413.         error.id = gui_errno = M_INVALID_PARMS;
  1414.         error.data.ptr_data = listbox_allocate_page;
  1415.         message_send(&error);
  1416.         return 0;
  1417.         }
  1418.     return 1;
  1419.     }
  1420.  
  1421.  
  1422. /* mark active selection in list box */
  1423. static void listbox_mark(LISTBOX *list)
  1424.     {
  1425.     fg_msm_hidecursor();
  1426.     fg_fillbox(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,list->marker);    /* erase old marker */
  1427.     if (list->first_page->next_page != NULL || list->first_page->number_of_items != 0)
  1428.         fg_putc(COLOR_DIALOG_SELECTION,FG_MODE_SET,~0,FG_ROT0,list->marker[FG_X1],list->marker[FG_Y2]-gui_char_height*(list->screen_offset+1),LIST_RIGHTARROW,list->marker);
  1429.     fg_msm_showcursor();
  1430.     fg_flush();
  1431.     }
  1432.  
  1433.  
  1434. /* scroll the listbox by the number of lines, returns 1 if OK or 0 if failed */
  1435. static short listbox_scroll(LISTBOX *list,short number_of_lines)
  1436.     {
  1437.     short height,ret;
  1438.     LISTBOX_PAGE *lp;
  1439.     short page_offset,height_count;
  1440.  
  1441.     ret = 1;
  1442.     height = list->height/DIALOG_UNITS;
  1443.     if (number_of_lines < 0)    /* scroll up */
  1444.         {
  1445.         if (list->screen_offset + number_of_lines >= 0)
  1446.             list->screen_offset += number_of_lines;     /* just move marker */
  1447.         else
  1448.             {                   /* redraw page */
  1449.             while (number_of_lines)
  1450.                 {
  1451.                 if (list->page_offset == 0)
  1452.                     {       /* get previous page */
  1453.                     if (list->current_page->previous_page == NULL)
  1454.                         {   /* no more previous pages */
  1455.                         list->screen_offset += number_of_lines;
  1456.                         if (list->screen_offset < 0)
  1457.                             list->screen_offset = 0;
  1458.                         break;
  1459.                         }
  1460.                     else
  1461.                         {   /* point to previous page */
  1462.                         list->current_page = list->current_page->previous_page;
  1463.                         list->page_offset = list->current_page->number_of_items;
  1464.                         }
  1465.                     }
  1466.                 list->page_offset--;
  1467.                 number_of_lines++;
  1468.                 }
  1469.             listbox_draw_contents(list);
  1470.             }
  1471.         listbox_mark(list);
  1472.         }
  1473.     else if (number_of_lines > 0)   /* scroll down */
  1474.         {
  1475.         for (lp=list->current_page, page_offset=list->page_offset, height_count=0 ; height_count < height-1 ; height_count++)
  1476.             if (++page_offset >= lp->number_of_items)   /* get pointer at bottom of screen */
  1477.                 {
  1478.                 if ((lp = lp->next_page) == NULL) break;
  1479.                 page_offset = 0;
  1480.                 }
  1481.         if (lp == NULL || list->screen_offset+number_of_lines < height)
  1482.             {       /* move within current screen or partially filled screen */
  1483.             list->screen_offset += number_of_lines;
  1484.             if (list->screen_offset > height_count)
  1485.                 list->screen_offset = height_count;
  1486.             }
  1487.         else
  1488.             {               /* redraw page */
  1489.             while (number_of_lines)
  1490.                 {
  1491.                 if (++page_offset >= lp->number_of_items)
  1492.                     {       /* need more pages */
  1493.                     if (lp->next_page == NULL)
  1494.                         {
  1495.                         ret = listbox_allocate_page(list,LISTBOX_SUCCEEDING_PAGES);
  1496.                         if (ret == 0 || lp->next_page == NULL)
  1497.                             {       /* nothing actually added */
  1498.                             list->status |= DIALOG_COMPLETED;
  1499.                             break;
  1500.                             }
  1501.                         }
  1502.                     lp = lp->next_page;
  1503.                     page_offset = 0;
  1504.                     }
  1505.                 list->page_offset++;
  1506.                 if (list->page_offset >= list->current_page->number_of_items)
  1507.                     {       /* get next page */
  1508.                     if (list->current_page->next_page == NULL)
  1509.                         {   /* this code should not be reached but is included as a safety plug */
  1510.                         list->page_offset--;
  1511.                         break;
  1512.                         }
  1513.                     list->current_page = list->current_page->next_page;
  1514.                     list->page_offset = 0;
  1515.                     }
  1516.                 number_of_lines--;
  1517.                 }
  1518.             if (list->screen_offset + number_of_lines >= height)
  1519.                 {   /* still want more? move to bottom of page */
  1520.                 list->screen_offset = height-1;
  1521.                 }
  1522.             listbox_draw_contents(list);
  1523.             }
  1524.         listbox_mark(list);
  1525.         }
  1526.     return ret;
  1527.     }
  1528.  
  1529.  
  1530. /* return current data for listbox at offset from top, or NULL if none */
  1531. static char *listbox_current_data(LISTBOX *list,short offset)
  1532.     {
  1533.     LISTBOX_PAGE *lp;
  1534.     short page_offset;
  1535.  
  1536.     for (lp=list->current_page, page_offset=list->page_offset ; offset > 0 ; offset--)
  1537.         {
  1538.         page_offset++;
  1539.         if (page_offset >= lp->number_of_items)
  1540.             {       /* get next page */
  1541.             if (lp->next_page == NULL)
  1542.                 return NULL;
  1543.             lp = lp->next_page;
  1544.             page_offset = 0;
  1545.             }
  1546.         }
  1547.     return lp->listbox_items + page_offset * (list->width/DIALOG_UNITS + 1);
  1548.     }
  1549.  
  1550.  
  1551. /* ---------------- EDITBOXES ---------------- */
  1552.  
  1553. /* verify parameters and open an editbox */
  1554. static short editbox_open(short x,short y,EDITBOX *edit,fg_pbox_t area,DIALOG_ITEM *d)
  1555.     {
  1556.     fg_box_t temp;
  1557.  
  1558.     if (edit->edit_width < 1 || edit->edit_width < edit->screen_width/DIALOG_UNITS ||
  1559.         edit->edit_string == NULL || (edit->status & ~DIALOG_BITS))
  1560.         return M_INVALID_PARMS;
  1561.     if (is_active(*edit))
  1562.         {
  1563.         temp[FG_X1] = x+(gui_char_width*edit->loc_x)/DIALOG_UNITS;
  1564.         temp[FG_Y1] = y+(gui_char_height*edit->loc_y)/DIALOG_UNITS;
  1565.         temp[FG_X2] = temp[FG_X1]+gui_char_width*(edit->screen_width/DIALOG_UNITS)+4;
  1566.         temp[FG_Y2] = temp[FG_Y1]+gui_char_height+2;
  1567.         fg_boxclip(fg.displaybox,temp,temp);
  1568.         fg_box_cpy(edit->screen,temp);
  1569.         fg_box_cpy(d->focus,temp);
  1570.         fg_drawbox(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_LINE_SOLID,temp,area);
  1571.         edit->status |= DIALOG_OPENED;
  1572.         editbox_initialize(edit);
  1573.         }
  1574.     else
  1575.         d->dialog_state |= DIALOG_FOCUS_SKIP;
  1576.     return 0;
  1577.     }
  1578.  
  1579.  
  1580. /* strip trailing whitespace from string and mark as unopened */
  1581. static void editbox_close(EDITBOX *edit)
  1582.     {
  1583.     short i;
  1584.  
  1585.     if (edit->status & DIALOG_OPENED)
  1586.         {
  1587.         edit->status &= ~DIALOG_OPENED;
  1588.         for (i = edit->edit_width-1 ; i >= 0 ; i--)
  1589.             if (edit->edit_string[i] == ' ')
  1590.                 edit->edit_string[i] = 0;
  1591.             else
  1592.                 break;
  1593.         }
  1594.     }
  1595.  
  1596.  
  1597. /* draw the editbox contents starting from scroll_offset and place cursor */
  1598. static void editbox_draw(EDITBOX *edit)
  1599.     {
  1600.     fg_box_t temp;
  1601.     short c,screen_width;
  1602.     char *p;
  1603.  
  1604.     p = edit->edit_string + edit->scroll_offset;
  1605.     screen_width = edit->screen_width/DIALOG_UNITS;
  1606.     fg_msm_hidecursor();
  1607.     fg_box_cpy(temp,edit->screen);
  1608.     temp[FG_X1]++;
  1609.     temp[FG_Y1]++;
  1610.     temp[FG_X2]--;
  1611.     temp[FG_Y2]--;
  1612.     fg_fillbox(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,temp);
  1613.     c = p[screen_width];
  1614.     p[screen_width] = 0;
  1615.     fg_puts(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_ROT0,temp[FG_X1],temp[FG_Y1],p,edit->screen);
  1616.     p[screen_width] = c;
  1617.     editbox_cursor(edit);
  1618.     fg_msm_showcursor();
  1619.     fg_flush();
  1620.     }
  1621.  
  1622.  
  1623. /* move the editbox cursor */
  1624. static void editbox_cursor(EDITBOX *edit)
  1625.     {
  1626.     short x,y;
  1627.  
  1628.     x = edit->screen[FG_X1] + 1;
  1629.     y = edit->screen[FG_Y1] + 1;
  1630.     fg_msm_hidecursor();
  1631.     fg_putc(COLOR_DIALOG_BACKGROUND,FG_MODE_SET,~0,FG_ROT0,x+(edit->curpos-edit->scroll_offset)*gui_char_width,y,(edit->curtype)?(EDITBOX_CURSOR_INSERT):(EDITBOX_CURSOR_OVERWRITE),edit->screen);
  1632.     fg_putc(COLOR_DIALOG_FOREGROUND,FG_MODE_SET,~0,FG_ROT0,x+(edit->curpos-edit->scroll_offset)*gui_char_width,y,edit->edit_string[edit->curpos],edit->screen);
  1633.     fg_putc(COLOR_DIALOG_SELECTION,FG_MODE_SET,~0,FG_ROT0,x+(edit->xpos-edit->scroll_offset)*gui_char_width,y,(edit->insert)?(EDITBOX_CURSOR_INSERT):(EDITBOX_CURSOR_OVERWRITE),edit->screen);
  1634.     edit->curpos = edit->xpos;
  1635.     edit->curtype = edit->insert;
  1636.     fg_msm_showcursor();
  1637.     fg_flush();
  1638.     }
  1639.  
  1640.  
  1641. /* using key, edit the line in the editbox.
  1642.  * If any edit changes were made return 2, if the key was consumed return 1,
  1643.  * else return 0 */
  1644. static short editbox_edit(EDITBOX *edit,short key)
  1645.     {
  1646.     short ret,width,i,x,scrolled,len;
  1647.     char *str;
  1648.  
  1649.     ret = scrolled = 0;             /* preset variables */
  1650.     x = edit->xpos;
  1651.     width = edit->edit_width;
  1652.     str = edit->edit_string;
  1653.     switch (key)
  1654.     {
  1655.     case LEFTARROW:                 /* move left */
  1656.         if (x > 0)
  1657.             x--;
  1658.         ret = 1;
  1659.         break;
  1660.     case RIGHTARROW:                /* move right */
  1661.         if (str[x] == 0)
  1662.             {
  1663.             str[x+1] = 0;
  1664.             str[x] = ' ';
  1665.             }
  1666.         if (x < width-1)
  1667.             x++;
  1668.         ret = 1;
  1669.         break;
  1670.     case EDITBOX_HOME:              /* move to beginning */
  1671.         x = 0;
  1672.         ret = 1;
  1673.         break;
  1674.     case EDITBOX_END:                   /* move to end */
  1675.         for (x = strlen(str) ; x > 0 ; x--)
  1676.             if (str[x-1] != ' ')
  1677.                 break;
  1678.         if (x >= width)
  1679.             x--;
  1680.         ret = 1;
  1681.         break;
  1682.     case INS:                       /* toggle insert mode */
  1683.         edit->insert ^= 1;
  1684.         ret = 1;
  1685.         break;
  1686.     case DELETE:                    /* delete at cursor */
  1687.         for (i = x ; i < strlen(str) ; i++)
  1688.             str[i] = str[i+1];
  1689.         ret = 2;
  1690.         break;
  1691.     case EDITBOX_DELETE_EOL:        /* delete to end of line */
  1692.         str[x] = 0;
  1693.         ret = 2;
  1694.         break;
  1695.     case BKSP:                      /* delete to right */
  1696.         if (x == 0)
  1697.             break;
  1698.         for (i = --x ; i < strlen(str) ; i++)
  1699.             str[i] = str[i+1];
  1700.         ret = 2;
  1701.         break;
  1702.     default:                        /* if printable, print it */
  1703.         if (!isprint_ibm(key))
  1704.             break;
  1705.         if (edit->insert)
  1706.             {
  1707.             len = strlen(str);
  1708.             if (len < width)
  1709.                 str[len+1] = 0;
  1710.             else
  1711.                 len--;
  1712.             for (i = len ; i > x ; i--)
  1713.                 str[i] = str[i-1];
  1714.             }
  1715.         else
  1716.             if (str[x] == 0)
  1717.                 str[x+1] = 0;
  1718.         str[x] = key;
  1719.         if (x < width-1)
  1720.             x++;
  1721.         ret = 2;
  1722.         break;
  1723.         }
  1724.     edit->xpos = x;
  1725.     if (x < edit->scroll_offset)
  1726.         {
  1727.         edit->scroll_offset = x;
  1728.         scrolled = 1;
  1729.         }
  1730.     if (x >= edit->scroll_offset+edit->screen_width/DIALOG_UNITS)
  1731.         {
  1732.         edit->scroll_offset = x - edit->screen_width/DIALOG_UNITS + 1;
  1733.         scrolled = 1;
  1734.         }
  1735.     if (ret == 2 || scrolled == 1)  /* rewrite editbox if changed or scrolled */
  1736.         editbox_draw(edit);
  1737.     if (ret == 1 && scrolled == 0)  /* just move cursor if changed */
  1738.         editbox_cursor(edit);
  1739.     return ret;
  1740.     }
  1741.